package com.rm.zeyou.advice;

import com.rm.zeyou.annotation.RepeatSubmit;
import com.rm.zeyou.exception.ErrorCodeException;
import com.rm.zeyou.util.redis.RedisUtil;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;

// 开启日志，需要依赖lombok
@Slf4j
// 把一个类定义为切面供容器读取
@Aspect
@Component
public class RepeatSubmitAspect {

    @Resource
    private RedisUtil redisUtil;

    @Pointcut("@annotation(com.rm.zeyou.annotation.RepeatSubmit)")
    public void pointcut() {
    }

    // 这是一个环绕通知，它会围绕被 @RepeatSubmit 注解标记的方法执行,这里的 repeatSubmit 与下面的参数对应
    @Around("pointcut()")
    public Object around(ProceedingJoinPoint point) throws Throwable {

        // 获取用户的token验证,这里项目用的是 header 里的  Authorization 参数
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        String requestToken = request.getHeader("Authorization");

        // 获取注解
        MethodSignature signature = (MethodSignature) point.getSignature();
        Method method = signature.getMethod();
        RepeatSubmit repeatSubmit = method.getAnnotation(RepeatSubmit.class);
        // 获取类，方法
        String className = method.getDeclaringClass().getName();
        String methodName = method.getName();

        // 组装key：用户唯一标识+操作类+方法
        String key = requestToken + "#" + className + "#" + methodName;
        String keyHashCode = String.valueOf(Math.abs(key.hashCode()));
        log.info("key:{},keyHashcode:{}", key, keyHashCode);

        //获取超时时间
        int timeOut = repeatSubmit.timeout();
        log.info("超时时间{}", timeOut);

        //  从缓存给中根据key获取数据
        String value = redisUtil.get(keyHashCode);

        if (value != null) {
            log.info("重复提交");
            // 如果value不为空; return  "请勿重复提交";
            throw  new ErrorCodeException("500", repeatSubmit.message());

        } else {
            log.info("首次提交");
            // value为空，则加入缓存，并设置过期过期时间
            redisUtil.set(keyHashCode, "1", timeOut);
        }

        //执行Object

        return point.proceed();
    }
}

